/**
 * 
 */
package com.loki.pdfSignature.tools;

import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.math.BigInteger;
import java.security.KeyPair;
import java.security.KeyPairGenerator;
import java.security.KeyStore;
import java.security.KeyStore.PasswordProtection;
import java.security.KeyStore.PrivateKeyEntry;
import java.security.KeyStoreException;
import java.security.NoSuchAlgorithmException;
import java.security.PrivateKey;
import java.security.PublicKey;
import java.security.UnrecoverableEntryException;
import java.security.cert.Certificate;
import java.security.cert.CertificateException;
import java.security.cert.CertificateFactory;
import java.security.cert.X509Certificate;
import java.util.Date;
import java.util.List;

import org.apache.commons.lang3.RandomStringUtils;
import org.apache.commons.lang3.StringUtils;
import org.bouncycastle.asn1.x500.RDN;
import org.bouncycastle.asn1.x500.X500Name;
import org.bouncycastle.asn1.x509.Extension;
import org.bouncycastle.cert.X509CertificateHolder;
import org.bouncycastle.cert.X509v3CertificateBuilder;
import org.bouncycastle.cert.jcajce.JcaX509v3CertificateBuilder;
import org.bouncycastle.operator.ContentSigner;
import org.bouncycastle.operator.jcajce.JcaContentSignerBuilder;
import org.springframework.util.Base64Utils;
import org.springframework.util.ResourceUtils;


/**
 * @author loki
 *
 */
public class CertificateIssuer {

	private static final long ONE_DAY = 1000L * 60 * 60 * 24;
	
	private static final long YEARS = 1000L * 60 * 60 * 24 * 365 * 10;
	
	private static final String ALGORITHM = "SHA256withRSA";
	/**
	 * 
	 * @return 
	 * @return
	 * @throws Exception
	 */
	public CertificateInfo issue(Long ownerId,String commonName,String emailAddress){
		try {
			//1.加载CA证书
			PrivateKeyEntry caEntry = loadCA(ownerId);
			//2.生成密钥对
			KeyPair keyPair = genKeyPair();
			//3.用CA证书签发客户证书
			String subject = "C=CN, ST=Shanghai, L=Shanghai, O=\"Shanghai Jupai Netcom Science Technology Co., Ltd\", OU=Online Finantial,"
							+"CN="+commonName+" ,E="+emailAddress;
			
			X509Certificate caCert = (X509Certificate) caEntry.getCertificate();  
			
			X500Name issuer = new X500Name(caCert.getIssuerDN().toString());
			Certificate cert = generateV3(issuer, new X500Name(subject),  
					            BigInteger.ZERO, 
					            new Date(System.currentTimeMillis() - ONE_DAY),  
					            new Date(System.currentTimeMillis() + YEARS), 
					            keyPair.getPublic(),//待签名的公钥  
					            caEntry.getPrivateKey()//CA的私钥  
					            , null); 
			//4.保存证书
			return store(keyPair.getPrivate(), cert, caEntry.getCertificate(), commonName);
		} catch (Exception e) {
			e.printStackTrace();
		}
		return null;
	}
	
	/**
	 * load CA certificate from database by customer id 
	 * @param ownerId 
	 * @return
	 * @throws Exception
	 */
	public PrivateKeyEntry loadCA(Long ownerId) throws Exception {
		//TODO 从数据库读取CA证书的JKS文件  
		String pass="123456";
		String alias = "cacert";
		String content = "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";
		
		KeyStore store=KeyStore.getInstance("JKS");
		store.load(new ByteArrayInputStream(Base64Utils.decodeFromString(content)),
					pass.toCharArray());
		
		PrivateKeyEntry caEntry = (PrivateKeyEntry) store.getEntry(alias, new PasswordProtection(pass.toCharArray()));
		return caEntry;
	}  
	
	/**
	 * 生成待签名的密钥对
	 * @return
	 * @throws NoSuchAlgorithmException
	 */
	public KeyPair genKeyPair() throws NoSuchAlgorithmException {
		KeyPairGenerator kpg = KeyPairGenerator.getInstance("RSA");  
		kpg.initialize(2048);  
		KeyPair keyPair = kpg.generateKeyPair();
		return keyPair;
	}

	/**
	 * 用CA证书签发客户证书
	 * @param issuer 证书颁发者
	 * @param subject 证书使用者
	 * @param serial 客户证书序列号
	 * @param notBefore 证书有效期从
	 * @param notAfter 证书有效期到
	 * @param clientPub 客户证书公钥
	 * @param caPrivate CA证书私钥
	 * @param extensions 证书扩展项
	 * @return
	 * @throws Exception
	 */
	public Certificate generateV3(X500Name issuer, X500Name subject,  
		    BigInteger serial, Date notBefore, Date notAfter,  
		    PublicKey clientPub, PrivateKey caPrivate, List<Extension> extensions)  
		    throws Exception {  
		
			X509v3CertificateBuilder builder = new JcaX509v3CertificateBuilder(  
			        issuer, serial, notBefore, notAfter,  
			        subject, clientPub);  
			ContentSigner sigGen = new JcaContentSignerBuilder(ALGORITHM).build(caPrivate);  
			//privKey是CA的私钥，publicKey是待签名的公钥，那么生成的证书就是被CA签名的证书。  
			if (extensions != null)  
			    for (Extension ext : extensions) {  
			        builder.addExtension(ext.getExtnId(),  
			                ext.isCritical(),  
			                ext.getParsedValue());  
			    }  
			X509CertificateHolder holder = builder.build(sigGen);  
			CertificateFactory cf = CertificateFactory.getInstance("X.509");  
			InputStream is1 = new ByteArrayInputStream(holder.toASN1Structure()  
			        .getEncoded());  
			X509Certificate theCert = (X509Certificate) cf.generateCertificate(is1);  
			is1.close();  
			return theCert;  
		} 
	
	/**
	 * 用KeyEntry形式存储一个私钥以及对应的证书，并把CA证书加入到它的信任证书列表里面。  
	 * @param key
	 * @param cert
	 * @param caCert
	 * @param alias
	 * @throws Exception
	 */
	public CertificateInfo store(PrivateKey key, Certificate cert,  
	    Certificate caCert, String alias) throws Exception {  
		String pass = RandomStringUtils.randomNumeric(8);
		KeyStore store = KeyStore.getInstance("JKS");  
		store.load(null, null);  
		store.setKeyEntry(alias, key, pass.toCharArray(), new Certificate[] {  
		        cert, caCert });
		
		ByteArrayOutputStream out = new ByteArrayOutputStream();
		store.store(out, pass.toCharArray());
		String content = Base64Utils.encodeToString(out.toByteArray());
		//TODO save to database
		CertificateInfo certificateInfo = new CertificateInfo();
		certificateInfo.setCode(alias);
		certificateInfo.setContent(content);
		certificateInfo.getProperties().setProperty("pass", pass);
		certificateInfo.setState(true);
		certificateInfo.setType(1);//JKS
		return certificateInfo;
	}
	
}
